You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
124 lines
4.1 KiB
124 lines
4.1 KiB
<script setup lang="ts">
|
|
const route = useRoute()
|
|
const id = route.params.id as string
|
|
|
|
const { data, refresh } = await useHttpFetch(`/api/scheduler/tasks/${id}`)
|
|
const task = computed(() => data.value?.task)
|
|
const recentExecutions = computed(() => data.value?.recentExecutions ?? [])
|
|
|
|
async function handleTrigger() {
|
|
await $fetch(`/api/scheduler/tasks/${id}/trigger`, { method: "POST" })
|
|
}
|
|
|
|
async function handleToggle() {
|
|
if (!task.value) return
|
|
await $fetch(`/api/scheduler/tasks/${id}/toggle`, {
|
|
method: "POST",
|
|
body: { enabled: !task.value.enabled },
|
|
})
|
|
refresh()
|
|
}
|
|
|
|
function statusColor(status: string): "success" | "error" | "warning" | "neutral" {
|
|
switch (status) {
|
|
case "success": return "success"
|
|
case "failed": return "error"
|
|
case "running": return "warning"
|
|
default: return "neutral"
|
|
}
|
|
}
|
|
|
|
function timeAgo(ts: number): string {
|
|
const diff = Date.now() - ts
|
|
const mins = Math.floor(diff / 60000)
|
|
if (mins < 1) return "just now"
|
|
if (mins < 60) return `${mins}m ago`
|
|
const hours = Math.floor(mins / 60)
|
|
if (hours < 24) return `${hours}h ago`
|
|
return `${Math.floor(hours / 24)}d ago`
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<div class="p-6 max-w-4xl mx-auto">
|
|
<div class="mb-4">
|
|
<ULink to="/admin/scheduler" class="text-sm text-gray-500">← Back to tasks</ULink>
|
|
</div>
|
|
|
|
<div v-if="task" class="space-y-6">
|
|
<!-- Task header -->
|
|
<div class="flex items-center justify-between">
|
|
<div>
|
|
<h1 class="text-2xl font-bold">{{ task.name }}</h1>
|
|
<p class="text-sm text-gray-500 mt-1">
|
|
{{ task.cronExpression }} · {{ task.type }}
|
|
</p>
|
|
</div>
|
|
<div class="flex gap-2">
|
|
<UButton variant="outline" @click="handleTrigger">Trigger Now</UButton>
|
|
<UButton variant="outline" @click="handleToggle">
|
|
{{ task.enabled ? 'Pause' : 'Resume' }}
|
|
</UButton>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Task config -->
|
|
<div class="rounded-lg border p-4">
|
|
<h2 class="font-semibold mb-3">Configuration</h2>
|
|
<dl class="grid grid-cols-2 gap-2 text-sm">
|
|
<dt class="text-gray-500">Type</dt>
|
|
<dd>{{ task.type }}</dd>
|
|
<template v-if="task.type === 'function'">
|
|
<dt class="text-gray-500">Function</dt>
|
|
<dd>{{ task.functionName }}</dd>
|
|
<dt class="text-gray-500">Payload</dt>
|
|
<dd><code>{{ task.functionPayload }}</code></dd>
|
|
</template>
|
|
<template v-if="task.type === 'http'">
|
|
<dt class="text-gray-500">Method</dt>
|
|
<dd>{{ task.httpMethod }}</dd>
|
|
<dt class="text-gray-500">URL</dt>
|
|
<dd>{{ task.httpUrl }}</dd>
|
|
</template>
|
|
<dt class="text-gray-500">Catch Up</dt>
|
|
<dd>{{ task.catchUp ? 'Yes' : 'No' }}</dd>
|
|
<dt class="text-gray-500">Retries</dt>
|
|
<dd>{{ task.maxRetries }}</dd>
|
|
<dt class="text-gray-500">Timeout</dt>
|
|
<dd>{{ task.timeoutSeconds }}s</dd>
|
|
<dt class="text-gray-500">Created</dt>
|
|
<dd>{{ new Date(task.createdAt).toLocaleString() }}</dd>
|
|
</dl>
|
|
</div>
|
|
|
|
<!-- Execution history -->
|
|
<div class="rounded-lg border">
|
|
<h2 class="font-semibold p-4 border-b">Recent Executions</h2>
|
|
<div v-if="recentExecutions.length === 0" class="p-4 text-sm text-gray-400">
|
|
No executions yet
|
|
</div>
|
|
<div v-else>
|
|
<div
|
|
v-for="log in recentExecutions"
|
|
:key="log.id"
|
|
class="flex items-center gap-3 p-3 border-b last:border-b-0"
|
|
>
|
|
<UBadge :color="statusColor(log.status)" variant="subtle" size="sm">
|
|
{{ log.status }}
|
|
</UBadge>
|
|
<span class="text-sm text-gray-500 flex-1">
|
|
{{ timeAgo(log.startedAt) }}
|
|
</span>
|
|
<span v-if="log.resultSummary" class="text-sm text-gray-600">
|
|
{{ log.resultSummary }}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div v-else-if="data" class="text-gray-400">
|
|
Task not found.
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|